using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.MultiTenancy;
using Abp.Runtime.Security;
using Abp.UI;
using Yozeev.Authentication.External;
using Yozeev.Authentication.JwtBearer;
using Yozeev.Authorization;
using Yozeev.Models.TokenAuth;
using Yozeev.MultiTenancy;
using Yozeev.UserManagerment.Users;
using Abp.Runtime.Caching;
using Yozeev.Authorization.Impersonation;
using Abp;
using Abp.Domain.Uow;
using Abp.IdentityFramework;
using Abp.Json;
using L._52ABP.Common.Consts;
using Yozeev.Authentication.External.ExternalAuth;
using Yozeev.Authentication.External.ExternalAuth.Dto;
using Yozeev.DataFileObjects;
using Yozeev.DataFileObjects.DataTempCache;
using Yozeev.Security.Captcha;
using Yozeev.UserManagerment.Users.UserLink;
using Abp.Extensions;
using L._52ABP.Common.Net.MimeTypes;
using L._52ABP.Core.VerificationCodeStore;
using Yozeev.BusinessLogic.DomainService;
using Yozeev.Models;
using Yozeev.BusinessLogic;
using Yozeev.EntityFrameworkCore;
using Yozeev.SystemConfig.BasicConfig.DomainService;
using Yozeev.BusinessLogic.Stats.Dtos;
using Abp.Domain.Entities.Auditing;
using DotNetCore.CAP;
using Yozeev.Common;
using Yozeev.SystemConfig.DomainService;
using Yozeev.BusinessLogic.Dtos;
using Abp.AutoMapper;
using Yozeev.SystemConfig;
using Yozeev.SystemConfig.Dtos;
using Yozeev.Common.Print;

namespace Yozeev.Controllers
{
    [Route("api/[controller]/[action]")]
    public class ActivityController : CommonController//YozeevControllerBase
    {
        private readonly ITenantCache _tenantCache;
        private readonly ICacheManager _cacheManager;
        private readonly IImpersonationManager _impersonationManager;
        private readonly IUserLinkManager _userLinkManager;
        private readonly IdentityOptions _identityOptions;
        private readonly IDataTempFileCacheManager _dataTempFileCacheManager;
        private readonly IDataFileObjectManager _dataFileObjectManager;
        private readonly ActivityManager _activityManager;
        //private readonly SourceManager _sourceManager;
        private readonly TicketDetailManager _ticketDetailManager;
        private readonly ICapPublisher _capBus;
        private readonly PrintStyleManager _printStyleManager;

        public ActivityController(
            ITenantCache tenantCache,
            ICacheManager cacheManager,
            IImpersonationManager impersonationManager,
            IUserLinkManager userLinkManager,
            IOptions<IdentityOptions> identityOptions,
            UserManager userManager, 
            IDataFileObjectManager dataFileObjectManager, 
            IDataTempFileCacheManager dataTempFileCacheManager
            , ActivityManager activityManager
            , SourceManager sourceManager
            , ScheduleManager scheduleManager
            , PayMethodManager payMethodManager
            , TicketPriceManager ticketPriceManager
            , CustomerManager customerManager
            , TicketDetailManager ticketDetailManager
            , ICapPublisher capBus
            , TravelAgencyManager travelManager
            , PrintStyleManager printStyleManager
            ) :base(sourceManager, scheduleManager, payMethodManager, cacheManager, ticketPriceManager, customerManager, userManager, travelManager)
        {
            _tenantCache = tenantCache;
            _cacheManager = cacheManager;
            _impersonationManager = impersonationManager;
            _userLinkManager = userLinkManager;
            _identityOptions = identityOptions.Value;
            _dataFileObjectManager = dataFileObjectManager;
            _dataTempFileCacheManager = dataTempFileCacheManager;
            _activityManager = activityManager;
            _ticketDetailManager = ticketDetailManager;
            _capBus = capBus;
            _printStyleManager = printStyleManager;
        }
        /// <summary>
        /// Web客户端使用，直接将订单创建到activity表中
        /// </summary>
        /// <param name="createActivityModel">
        /// {
        ///     "sourceId": "54D99CD6-D807-4783-70AA-08D798BCBD02",
        ///     "scheduleId": "829D2F50-D4F8-4D0C-0C2F-08D798BCBD32",
        ///     "payMethodId": "6253E959-5DFD-4CBA-0A7C-08D798BCBC89",
        ///     "activityDetails": [
        ///         {
        ///             "ticketPriceId": "2744AC36-68C4-45E0-1F19-08D798BCBD8A",
        ///             "customerId": "",
        ///         }
        ///     ]
        /// }
        /// </param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActivityResultModel> CreateActivity([FromBody]CreateActivityModel createActivityModel)
        {
            try
            {
                //判断提交数据的正确性
                var activity = this.IsGetActivity(createActivityModel);
                //创建订单
                ActivityResultModel activityResultModel = _activityManager.CreateActivity(activity);
                await _capBus.PublishAsync("swei.activity.create", activityResultModel.ActivityId);
                return activityResultModel;
            }
            catch (Exception ex)
            {
                return new ActivityResultModel()
                {
                    ResultCode = "001",
                    ResultMessage = ex.Message,
                    Detail = ex.StackTrace,
                };
            }
        }



        /// <summary>
        /// Web客户端使用，执行退票操作
        /// </summary>
        /// <param name="List">票据Idlist</param>
        /// <param name="rDiscount">退票折扣</param>
        /// <param name="remark">备注</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActivityResultModel> RefundTicket(List<Guid> List,decimal rDiscount, string remark = "")
        {
            try
            {
                //检验退票信息
                var ticketDetailList = CheckTickeDetailList(List);
                var result = _activityManager.RefundActivity(ticketDetailList, (long)AbpSession.UserId, rDiscount, remark);
                //修改航班剩余数
                ticketDetailList.ForEach(ticketDetail=> {
                    IsExistenTicket(ticketDetail.Schedule, -1, WareHousePosition.StandradPosition);
                });
                return result;
            }
            catch (Exception ex)
            {
                return new ActivityResultModel()
                {
                    ResultCode = "001",
                    ResultMessage = ex.Message,
                    Detail = ex.StackTrace,
                };
            }
        }
        /// <summary>
        /// 查询剩余该航班票数
        /// </summary>
        /// <param name="ScheduleId">航班Id</param>
        /// <returns></returns>
        [HttpPost]
        public long GetExistenTicket(Guid ScheduleId)
        {
            var schedule = GetSchedule(ScheduleId);
            return IsExistenTicket(schedule, 0, WareHousePosition.StandradPosition);
        }
        /// <summary>
        /// 设置预留票数
        /// </summary>
        /// <param name="ScheduleId">航班Id</param>
        /// <param name="ReserveQuantity">预留数</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActivityResultModel> SetReserveQuantity(Guid ScheduleId,long ReserveQuantity)
        {
            ActivityResultModel activityResult = new ActivityResultModel()
            {
                ResultCode = "000",
                ResultMessage = "设置成功"
            };
            try
            {
                var schedule = GetSchedule(ScheduleId);
                if (schedule.EndTime < DateTime.Now)
                {
                    throw new Exception("航班" + schedule.ScheduleCode + "售票结束");
                }
                if (schedule.SurplusQuantity > (ReserveQuantity - schedule.ReserveQuantity))
                {
                    schedule.SurplusQuantity -= ReserveQuantity - schedule.ReserveQuantity;
                    schedule.ReserveQuantity = ReserveQuantity;
                    TimeSpan slidingExpireTime = schedule.EndTime - DateTime.Now;
                    await GetICache().SetAsync(schedule.Id.ToString(), schedule, slidingExpireTime);
                    UpdateSchedule(schedule);
                }
                else
                {
                    throw new Exception("剩余票不够预留");
                }
                return activityResult;
            }
            catch (Exception ex)
            {
                return new ActivityResultModel()
                {
                    ResultCode = "001",
                    ResultMessage = ex.Message,
                    Detail = ex.StackTrace,
                };
            }
        }
        /// <summary>
        /// 设置各个仓位预留票数
        /// </summary>
        /// <param name="wareReserveQuantity">各个仓位预留数</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActivityResultModel> SetReserveQuantityByWare(WareReserveQuantity wareReserveQuantity)
        {
            ActivityResultModel activityResult = new ActivityResultModel()
            {
                ResultCode = "000",
                ResultMessage = "设置成功"
            };
            try
            {
                var schedule = GetSchedule(wareReserveQuantity.ScheduleId);
                if (schedule.EndTime < DateTime.Now)
                {
                    throw new Exception("航班" + schedule.ScheduleCode + "售票结束");
                }
                if (!wareReserveQuantity.remark.IsNullOrWhiteSpace())
                    schedule.Remark = wareReserveQuantity.remark;
                //标准仓剩余数
                var ticketQuantity = TicketQuantity.ModifyReserve(new TicketQuantity(schedule.StandardNum, schedule.StandardSurplusNum, schedule.StandardReserveNum), wareReserveQuantity.standardQuantity);
                schedule.StandardSurplusNum = ticketQuantity.surplusQuantity;
                schedule.StandardReserveNum = ticketQuantity.reserveQuantity;
                //vip仓剩余数
                ticketQuantity = TicketQuantity.ModifyReserve(new TicketQuantity(schedule.VIPNum, schedule.VIPSurplusNum, schedule.VIPReserveNum), wareReserveQuantity.vipQuantity);
                schedule.VIPSurplusNum = ticketQuantity.surplusQuantity;
                schedule.VIPReserveNum = ticketQuantity.reserveQuantity;
                //包间仓剩余数
                ticketQuantity = TicketQuantity.ModifyReserve(new TicketQuantity(schedule.CompartmentNum, schedule.CompartmentSurplusNum, schedule.CompartmentReserveNum), wareReserveQuantity.compartmentQuantity);
                schedule.CompartmentSurplusNum = ticketQuantity.surplusQuantity;
                schedule.CompartmentReserveNum = ticketQuantity.reserveQuantity;
                //总剩余数
                schedule.SurplusQuantity = schedule.StandardSurplusNum + schedule.VIPSurplusNum + schedule.CompartmentSurplusNum;
                schedule.ReserveQuantity = schedule.StandardReserveNum + schedule.VIPReserveNum + schedule.CompartmentReserveNum;
                //更新缓存和数据库
                TimeSpan slidingExpireTime = schedule.EndTime - DateTime.Now;
                await GetICache().SetAsync(schedule.Id.ToString(), schedule, slidingExpireTime);
                UpdateSchedule(schedule);
                return activityResult;
            }
            catch (Exception ex)
            {
                return new ActivityResultModel()
                {
                    ResultCode = "001",
                    ResultMessage = ex.Message,
                    Detail = ex.StackTrace,
                };
            }
        }
        /// <summary>
        /// 合计退票费用
        /// </summary>
        /// <param name="List"></param>
        /// <param name="rDiscount"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActivityResultModel> SumRefund(List<Guid> List, decimal rDiscount)
        {
            ActivityResultModel activityResult = new ActivityResultModel()
            {
                ResultCode = "000",
                ResultMessage = "合计成功"
            };
            try
            {
                decimal TotalAmout = 0;
                List<TicketDetail> ticketDetailList = _ticketDetailManager.GetTicketDetailList(List);
                //判断该票型是否可以出售
                if (ticketDetailList.Where(m => m.Schedule.StartTime < DateTime.Now).ToList().Count > 0)
                    throw new Exception("航班已开始航行");
                if (List.Count != ticketDetailList.Count)
                    throw new Exception("有异常数据");
                if (ticketDetailList.Where(m => m.TicketStatus == TicketStatusEnum.TicketRefund).ToList().Count > 0)
                    throw new Exception("存在已退票数据");
                if (ticketDetailList.Where(m => m.TicketStatus == TicketStatusEnum.Used).ToList().Count > 0)
                    throw new Exception("存在已使用的票");
                TotalAmout = ticketDetailList.Sum(m => _activityManager.getRefundAmount(m.ActivityDetail.TotalAmount * rDiscount));
                activityResult.Date = TotalAmout; 
                return activityResult;
            }
            catch (Exception ex)
            {
                return new ActivityResultModel()
                {
                    ResultCode = "001",
                    ResultMessage = ex.Message,
                    Detail = ex.StackTrace,
                };
            }
        }
        /// <summary>
        /// 有返回打印信息的查询，不做校验，web端使用
        /// </summary>
        /// <param name="TicketDetailIds">票据Id</param>
        /// <param name="printStyleCode">打印样式代码（创建样式的样式代码Core）</param>
        /// <returns>返回的是Lodop云打印的js语句</returns>
        [HttpPost]
        [AbpAuthorize]
        public async Task<string> GetPrintTicketByWeb(List<Guid> TicketDetailIds, string printStyleCode = "TicketBinding")
        {
            var ticketDetails = _ticketDetailManager.GetTicketDetailList(TicketDetailIds);
            return await _printStyleManager.GetLodopPrintString(ticketDetails, printStyleCode);
        }
        /// <summary>
        /// 返回每张票的打印信息，不做校验，数字为百分比，安卓端使用
        /// </summary>
        /// <param name="TicketDetailIds">票据Id</param>
        /// <param name="printStyleCode">打印样式代码（创建样式的样式代码Core）</param>
        /// <returns></returns>
        [HttpPost]
        [AbpAuthorize]
        public async Task<List<TicketDetailPrint>> GetPrintTicketByAndroid(List<Guid> TicketDetailIds, string printStyleCode = "TicketBinding")
        {
            var ticketDetails = _ticketDetailManager.GetTicketDetailList(TicketDetailIds);
            return await _printStyleManager.GetPrintPer(ticketDetails,printStyleCode);
        }

        #region 私有方法
        /// <summary>
        /// 判断提交数据是否有欠缺 
        /// </summary>
        /// <returns></returns>
        private Activity IsGetActivity(CreateActivityModel createActivityModel)
        {
            if (createActivityModel.PayMethodId.ToString().IsNullOrWhiteSpace())
                throw new Exception("支付方式不能为空");
            var payMethod = GetPayMethodList().FirstOrDefault(m => m.Id == createActivityModel.PayMethodId);
            if (payMethod == null)
                throw new Exception("查无该支付方式");

            if (createActivityModel.SourceId.ToString().IsNullOrWhiteSpace())
                throw new Exception("订单来源不能为空");
            var source = GetSourceList().FirstOrDefault(m => m.Id == createActivityModel.SourceId);
            if(source==null)
                throw new Exception("查无该订单来源");
            
            if (createActivityModel.activityDetails.Count<=0)
                throw new Exception("购票数不能为零");

            if (AbpSession.UserId == null)
            {
                throw new Exception("创建人不能为空");
            }

            var activity = new Activity() {
                PayMethodId = (Guid)createActivityModel.PayMethodId,
                PayMethod = payMethod,
                SourceId = (Guid)createActivityModel.SourceId,
                Source = source,
                ActivityDetails = new List<ActivityDetail>(),
                CreatorUserId = (long)AbpSession.UserId,
                OrderType = createActivityModel.OrderType,
            };
            if (!createActivityModel.Remark.IsNullOrWhiteSpace())
                activity.Remark = createActivityModel.Remark;
            if (activity.OrderType == Abp.Domain.Entities.Auditing.OrderTypeEnum.OrderTypeTravelAgency)
                activity.TravelAgencyId = createActivityModel.TravelAgencyId;
            createActivityModel.activityDetails.ForEach(m=> {
                if (m.ticketPriceId.ToString().IsNullOrWhiteSpace())
                    throw new Exception("金额不能为空");
                var ticketPrice = GetTicketPriceList().FirstOrDefault(t => t.Id == m.ticketPriceId);
                if(ticketPrice ==null)
                    throw new Exception("查无该票价信息");

                if (m.ScheduleId.ToString().IsNullOrWhiteSpace())
                    throw new Exception("航班不能为空");
                var schedule = GetSchedule(m.ScheduleId);
                if (schedule == null)
                    throw new Exception("查无该航班");
                //查看是否有剩余票
                IsExistenTicket(schedule, m.quantity, ticketPrice.WarePosition);
                //ticketPrice.Schedule = schedule;

                if (m.customerId.ToString().IsNullOrWhiteSpace())
                    throw new Exception("游客不能为空");
                var customer = GetCustomerById(m.customerId);
                if (customer == null)
                    throw new Exception("查无该游客");

                createActivityModel.TotalAmount += ticketPrice.Price;
                var activityDetail = new ActivityDetail()
                {
                    Customer = customer,
                    TicketPrice = ticketPrice,
                    Quantity = m.quantity,
                    Schedule = schedule,
                };
                activity.ActivityDetails.Add(activityDetail);
            });
            activity.TotalQuantity = createActivityModel.activityDetails.Count;
            activity.TotalAmount = activity.ActivityDetails.Sum(m => m.TicketPrice.Price * m.Quantity);

            return activity;
        }
        private List<TicketDetail> CheckTickeDetailList(List<Guid> List)
        {
            List<TicketDetail> ticketDetailList = _ticketDetailManager.GetTicketDetailList(List);
            //判断该票型是否可以出售
            if (ticketDetailList.Where(m => m.Schedule.StartTime < DateTime.Now).ToList().Count > 0)
                throw new Exception("航班已开始航行");
            if (List.Count != ticketDetailList.Count)
                throw new Exception("有异常数据");
            if (ticketDetailList.Where(m => m.TicketStatus == TicketStatusEnum.TicketRefund).ToList().Count > 0)
                throw new Exception("存在已退票数据");
            if (ticketDetailList.Where(m => m.TicketStatus == TicketStatusEnum.Used).ToList().Count > 0)
                throw new Exception("存在已使用的票");
            if (AbpSession.UserId == null)
            {
                throw new Exception("创建人不能为空");
            }
            return ticketDetailList;
        }
        #endregion
    }
}
